package core.syntatic;

import java.util.Stack;

import core.KeyWord;
import core.LexicalToken;
import core.Signal;
import core.Token;
import core.codeGeneration.CodeGenerator;
import core.error.ErrorHandler;
import core.error.SyntaxException;
import core.lexical.LexicalAnalyser;
import core.semantic.SemanticAnalyser;
import core.semantic.SemanticTuple;


/**
 * In our compiler model, the parser (SyntaticAnalyser) obtains a tokens 
 * from the lexical analyzer and verifies that the token can be generated 
 * by the grammar for the source language. We expect the parser to report 
 * any syntax errors in an intelligible fashion and to recover from commonly 
 * occurring errors to continue processing the remainder of the program.
 * Conceptually, for well-formed programs, the parser constructs a parse tree and
 * passes it to the rest of the compiler for further processing.
 */
public class SyntaticAnalyser {

	/**
	 * the lexical analyzer
	 */
	private LexicalAnalyser scanner;

	/**
	 * the lexical token
	 */
	private LexicalToken token;

	/**
	 * the error handler
	 */
	private final ErrorHandler errorHandler;

	/**
	 * the stack 
	 */
	private Stack<LexicalToken> buffer;

	private SemanticAnalyser semanticAnalyser;

	private CodeGenerator codeGenerator;
	
	/**
	 * Constructs a SyntaticAnalyzer using the given <code>LexicalAnalyzer</code> and <code>ErrorHandler</code>.
	 * @param scanner - the lexical analyzer
	 */
	public SyntaticAnalyser( LexicalAnalyser scanner ) {
		this.scanner = scanner;
		this.errorHandler = scanner.getErrorHandler();
		buffer = new Stack<LexicalToken>();
		semanticAnalyser = new SemanticAnalyser(scanner);
		codeGenerator = CodeGenerator.getInstace();
	}

	/**
	 * Add a new node (<code>LexicalToken</code>) to the top of the stack leaving previous node below.
	 */
	private void pushNewToken() {
		pushToken( scanner.nextToken() );
	}

	/**
	 * Add a new node (<code>LexicalToken</code>) to the top of the stack using the given token
	 * and leaving previous node below. 
	 * @param token
	 */
	private void pushToken( LexicalToken token ) {
		System.out.println(token.getToken());
		buffer.push( token );
	}

	/**
	 * Returns the current top element (<code>LexicalToken</code>) of the stack without removing it
	 * from the stack.
	 * @return the current top element of the stack.
	 */
	private LexicalToken peekToken(){
		return buffer.peek();
	}

	/**
	 * It does the syntatic and semantic analyse of the source provided.
	 */
	public void analyseIt(){
		pushNewToken();
		if ( isArrayType() ) {
			checkArrayVariableDeclaration();
		}else if ( isType() ) {
			checkVariableDeclaration();
		}else if ( isKeyWord( KeyWord.METHOD ) ) {
			checkMethodDeclaration();
		}else if ( isKeyWord( KeyWord.MAIN ) ) {
			checkMain();
		}else{
			throw new SyntaxException( "Unexpected token " + peekToken() );
		}
		if(!semanticAnalyser.getSemanticException().getErrors().isEmpty()){
			throw semanticAnalyser.getSemanticException();
		}
	}

	/**
	 * Check if the next token is a FORD predefined type.
	 * In FORD language there is not possibility to have a 
	 * variable of type void.
	 */
	private boolean isArrayType() {
		return isSignal( Signal.TYPE ) && isKeyWord( KeyWord.ARRAYOF );
	}

	/**
	 * Check if the next token is a FORD predefined type.
	 * In FORD language there is not possibility to have a 
	 * variable of type void.
	 */
	private boolean isType() {
		if( isKeyWord( KeyWord.VOID ) ){
			throw new SyntaxException("Void is not allowed as a variable type.");
		}
		return isSignal(Signal.TYPE);
	}

	/**
	 * Check if the next token is a valid FORD variable or method identifier.
	 */
	private void checkIdentifier() {
		pushNewToken();
		if (!peekToken().getCode().equals(Signal.IDENTIFIER)){
			throw new SyntaxException( "Identifier expected" );
		}
	}


	/**
	 * Check if the next construction in the source code is an array variable declaration 
	 * according to the rule:
	 * <blockquote> <code> ARRAYOF TYPE identifier[NUMBER];</code></blockquote>
	 */
	private void checkArrayVariableDeclaration() {
		pushNewToken();
		checkSignal(Signal.TYPE);
		checkIdentifier();

		LexicalToken token = buffer.pop();
		semanticAnalyser.addSemanticTuple(SemanticTuple.Class.ARRAY_VARIABLE, token,
				KeyWord.valueOf(buffer.peek().getToken().toUpperCase()));
		buffer.push(token);
		
		
		pushNewToken();
		checkSignal( Signal.OPENING_BRACKET );
		pushNewToken();
		checkSignal( Signal.NUMBER );
		pushNewToken();
		checkSignal( Signal.CLOSING_BRACKET );
		pushNewToken();
		checkSignal(Signal.END_OF_COMMAND);
		analyseIt();
	}

	/**
	 * Check if the next construction in the source code is a variable declaration 
	 * according to the rule:
	 * <blockquote> <code> TYPE identifier;</code></blockquote>
	 */
	private void checkVariableDeclaration() {
		checkIdentifier();

		LexicalToken token = buffer.pop();
		semanticAnalyser.addSemanticTuple(SemanticTuple.Class.VARIABLE, token,
				KeyWord.valueOf(buffer.peek().getToken().toUpperCase()));
		buffer.push(token);

		pushNewToken();
		checkSignal(Signal.END_OF_COMMAND);
		analyseIt();
	}
	
    /**
	 * Check if the next construction in the source code is a variable declaration.
	 * The expected sequence of tokens are:
	 * <ul>
	 * 		<li>The Type
	 * 		<li>An identifier
	 * 		<li>The end of command symbol <strong>";"</strong>
	 * </ul>
	 */
	private void checkMethodDeclaration() {
		pushNewToken();
		if ( isKeyWord(KeyWord.VOID) ) {
			checkMethodSignature();
			checkNonReturningMethod();
		}else if ( isType() ){
			checkMethodSignature();
			LexicalToken t1 = buffer.pop();
			LexicalToken t2 = buffer.pop();
			LexicalToken t3 = buffer.pop();
			LexicalToken token = buffer.pop();
			semanticAnalyser.addSemanticTuple(SemanticTuple.Class.METHOD_NAME, token,
					KeyWord.valueOf(buffer.peek().getToken().toUpperCase()));
			buffer.push(token);
			
			LexicalToken tokenTemp = buffer.pop();
			semanticAnalyser.push(KeyWord.valueOf(buffer.peek().getToken().toUpperCase()));
			buffer.push(tokenTemp);		

			buffer.push(t3);
			buffer.push(t2);
			buffer.push(t1);

			checkReturningMethod();
		}else{
			throw new SyntaxException("expecting a type.");
		}

		pushNewToken();
		if ( isKeyWord( KeyWord.METHOD ) ) {			
			checkMethodDeclaration();
		}else if ( isKeyWord( KeyWord.MAIN ) ) {
			checkMain();
		}else{
			throw new SyntaxException( "Unexpected token " + peekToken() );
		}
	}

	/**
	 * It checks if the method signature is syntaticly correct.
	 */
	private void checkMethodSignature() {
		checkIdentifier();
		pushNewToken();
		checkSignal( Signal.OPENING_PARENTHESES );
		pushNewToken();
		checkSignal( Signal.CLOSING_PARENTHESES );
		pushNewToken();
		checkSignal( Signal.OPENING_BRACE );
	}

	/**
	 * Verify if the next token represents a command.
	 * @return <code>true</code> if the next token represents a command.
	 */
	private boolean isCommand(){
		boolean flag = true;
		if ( isKeyWord(KeyWord.WRITE) ){
			checkWriteCommand();
		}else if ( isKeyWord(KeyWord.IF) ){
			checkIfCommand();
		}else if ( isKeyWord(KeyWord.WHILE) ){
			checkWhileCommand();
		}else if ( isSignal(Signal.IDENTIFIER) ){
			pushNewToken();

			//array
			if (isSignal(Signal.OPENING_BRACKET)){
				pushNewToken();
				if (isSignal(Signal.NUMBER)||isSignal(Signal.IDENTIFIER)){
					pushNewToken();
					checkSignal(Signal.CLOSING_BRACKET);
				}
			}
			checkAtributionCommand();
		}else{
			flag = false;
		}
		return flag;

	}

	/**
	 * Check if there is no returnin method in the source provided.
	 */
	private void checkNonReturningMethod() {
		pushNewToken();
		if ( isCommand() ){

		}else if ( isSignal(Signal.CLOSING_BRACE) ){
			return;
		}else{
			throw new SyntaxException("Unexpected token " + peekToken());
		}
		checkNonReturningMethod();
	}

	/**
	 * Check the syntaxe of the returning method.
	 */
	private void checkReturningMethod() {

		pushNewToken();
		if ( isCommand() ){

		}else if ( isKeyWord( KeyWord.RETURN )){
			checkReturnStatement();
			pushNewToken();
			if ( isSignal(Signal.CLOSING_BRACE) ){
				return;
			}else{
				throw new SyntaxException("Unreachable code" + peekToken() + " '}' was expected here!" );
			}
		}else{
			throw new SyntaxException("Unexpected token " + peekToken());
		}
		checkReturningMethod();
	}

	/**
	 * Check if the next construction in the source code is a main method declaration.
	 */
	private void checkMain() {
		pushNewToken();
		checkSignal( Signal.OPENING_BRACE );
		pushNewToken();
		checkBody();
		pushNewToken();
		checkSignal(Signal.EOF);
		codeGenerator.closeStream();
	}

	/**
	 * Check the body of the source provided.
	 */
	private void checkBody(){
		//pushNewToken();
		if ( isKeyWord(KeyWord.WRITE) ){
			checkWriteCommand();
		}else if ( isKeyWord(KeyWord.IF) ){
			System.out.println("if in");
			checkIfCommand();
			System.out.println("if out");
			checkBody();
		}else if ( isKeyWord(KeyWord.WHILE) ){
			checkWhileCommand();
		}else if ( isKeyWord(KeyWord.CALL) ){
			pushNewToken();
			checkSignal( Signal.OPENING_PARENTHESES );
			pushNewToken();
			checkSignal(Signal.IDENTIFIER);

			pushNewToken();

			checkSignal( Signal.CLOSING_PARENTHESES );
			pushNewToken();
			checkSignal(Signal.END_OF_COMMAND);
		}else if ( isSignal(Signal.IDENTIFIER) ){
			
			//Atributtion code generation <AG1>
			String leftSize = peekToken().getToken();
			
			pushNewToken();
			if ( isSignal(Signal.ATRIBUTION_OPERANT) ){
				checkAtributionCommand();
				
				//Atributtion code generation <AG2>
				String oper1 = codeGenerator.pop(CodeGenerator.Stack.PcO);
				codeGenerator.emit(leftSize, "=", oper1);
				
			}else if ( isSignal(Signal.OPENING_PARENTHESES) ){
				pushNewToken();
				checkSignal(Signal.CLOSING_PARENTHESES);
				pushNewToken();
				checkSignal(Signal.END_OF_COMMAND);
			}else if ( isSignal(Signal.OPENING_BRACKET) ){
				// Test array
				
				pushNewToken();
				if (isSignal(Signal.NUMBER) || isSignal(Signal.IDENTIFIER)){
					String aux = peekToken().getToken();
					pushNewToken();
					checkSignal(Signal.CLOSING_BRACKET);
					pushNewToken();
					checkSignal(Signal.ATRIBUTION_OPERANT);
					checkAtributionCommand();
					
					//Atributtion code generation <AG2>
					String oper1 = codeGenerator.pop(CodeGenerator.Stack.PcO);
					codeGenerator.emit(leftSize + "["+ aux + "]", "=", oper1);
					
				}else{
					throw new SyntaxException("Unexpected token " + peekToken());
				}
			}else{
				throw new SyntaxException("Unexpected token " + peekToken());
			}
		}else if ( isSignal(Signal.CLOSING_BRACE) ){
			return;
		}else{
			throw new SyntaxException("Unexpected token " + peekToken());
		}
		pushNewToken();
		checkBody();
	}

	/**
	 * It pushes the atributtion type of the token in the top of the stack.
	 * @since 17/03/2008
	 */
	private void asPushAtributionType() {
		
		LexicalToken token = buffer.pop();
		
		if(buffer.peek().getToken().equals("]")){
			//is array
			semanticAnalyser.pushIdentifierType(SemanticTuple.Class.ARRAY_VARIABLE, buffer);
		}else{
			semanticAnalyser.pushIdentifierType(SemanticTuple.Class.VARIABLE, buffer);
		}
		buffer.push(token);
	}


	/**
	 * Check if the next construction in the source code is a return statement.
	 */
	private void checkReturnStatement() {
		checkEvaluables();
		
		semanticAnalyser.verifyAtributionCompatibility();
		
		checkSignal( Signal.END_OF_COMMAND );
	}

	/**
	 * Check if the next construction in the source code is a key word.
	 * @param keyWord FORD key word.
	 */
	private boolean isKeyWord( KeyWord keyWord ){
		return keyWord.hasSameToken( peekToken().getToken() );
	}

	/**
	 * Check if the next construction in the source code is a signal.
	 * @param signal
	 */
	private boolean isSignal( Signal signal ){
		return peekToken().getCode().equals( signal );
	}

	/**
	 * Check if the next construction in the source code is a signal.
	 * @param signal
	 */
	private void checkSignal( Signal signal ){
		if ( !peekToken().getCode().equals( signal ) ){
			throw new SyntaxException("Signal expected: " + signal + " but was " + peekToken().getCode());
		}
	}


	/**
	 * Check if the next construction in the source code is a write command.
	 */
	private void checkWriteCommand() {
		pushNewToken();
		checkSignal( Signal.OPENING_PARENTHESES );
		pushNewToken();
		if (isSignal( Signal.STRING ) || isSignal( Signal.IDENTIFIER )){
			pushNewToken();
			if (isSignal( Signal.OPENING_BRACKET )){
				pushNewToken();
				if (isSignal(Signal.NUMBER) || isSignal(Signal.IDENTIFIER)){
					pushNewToken();
					checkSignal(Signal.CLOSING_BRACKET);
					pushNewToken();
					checkSignal(Signal.CLOSING_PARENTHESES);
					pushNewToken();
					checkSignal( Signal.END_OF_COMMAND );
				}else{
					throw new SyntaxException("Unexpected token " + peekToken());
				}
			}else if (isSignal( Signal.CLOSING_PARENTHESES)){
				pushNewToken();
				checkSignal( Signal.END_OF_COMMAND );
			}else{
				throw new SyntaxException("Unexpected token " + peekToken());
			}
		}else{
			throw new SyntaxException("Unexpected token " + peekToken());
		}
	}

	/**
	 * Check if the next construction in the source code is a if command.
	 */
	private void checkIfCommand() {
		pushNewToken();
		checkSignal( Signal.OPENING_PARENTHESES );
		pushNewToken();
		
		checkRelationalExpression();
		
		//Generation Code Action <AG4>
		String label = codeGenerator.makeLabel();
		codeGenerator.push(CodeGenerator.Stack.PcL, label);
		codeGenerator.emit(label, "jif");
		
		checkSignal( Signal.CLOSING_PARENTHESES );
		pushNewToken();
		checkSignal( Signal.OPENING_BRACE );
		pushNewToken();
		checkBody();
		
		//Generation code action <AG5>
		String labelAux = codeGenerator.pop(CodeGenerator.Stack.PcL);
		label = codeGenerator.makeLabel();
		codeGenerator.push(CodeGenerator.Stack.PcL, label);
		codeGenerator.emit(label, "jmp");
		codeGenerator.insert(labelAux, codeGenerator.getNextCommandLine());
		
		pushNewToken();
		checkElseCommand();
		label = codeGenerator.pop(CodeGenerator.Stack.PcL);
		codeGenerator.insert(label, codeGenerator.getNextCommandLine());
	}

	/**
	 * Check if the next construction in the source code is a logic expression.
	 */
	private void checkExpression() {
		if ( isBooleanTerm() ){
			return;
		}
		checkArithmeticExpression();
		if (isOperand()){
			
			String symbol = peekToken().getToken();
			
			checkCompositeExpression();
			semanticAnalyser.verifyRelationalTypeCompatibility();
			
			//Code Generation action to a relational expression
			String result = codeGenerator.makeTemp();
			codeGenerator.emit(result, symbol, codeGenerator.pop(CodeGenerator.Stack.PcO),
								peekToken().getToken());
			codeGenerator.push(CodeGenerator.Stack.PcO, result);
			
			asPushType(KeyWord.BOOLEAN);
			pushNewToken();
		}else{
			return;
		}
	}
	
	private void checkRelationalExpression(){
		
		// Generation code action <AG1>
		codeGenerator.resetTemp();
		
		//TODO Refatorar
		if(KeyWord.TRUE.hasSameToken( peekToken().getToken())  ||
				KeyWord.FALSE.hasSameToken( peekToken().getToken() )){
			
			//Arithmetic code generetion <AG6>
			codeGenerator.push(CodeGenerator.Stack.PcO, peekToken().getToken());
			asPushType(KeyWord.BOOLEAN);
			pushNewToken();
		}else{
			checkArithmeticExpression();
		}
		
		//Generation code action <AG2>
		String leftSize = codeGenerator.pop(CodeGenerator.Stack.PcO);
		if(isOperand()){
			
			//Generation code action <AG3>
			String relationalOp = peekToken().getToken();
			pushNewToken();
			
			if(isBooleanTerm()){
				
				//Arithmetic code generetion <AG6>
				codeGenerator.push(CodeGenerator.Stack.PcO, peekToken().getToken());
				asPushType(KeyWord.BOOLEAN);
				pushNewToken();
			}else{
				checkArithmeticExpression();
			}
			
			semanticAnalyser.verifyRelationalTypeCompatibility();
			
			//Generation code action <AG4>
			codeGenerator.emit(relationalOp, leftSize, 
						       codeGenerator.pop(CodeGenerator.Stack.PcO));
		}else{
			throw new RuntimeException("Relational operator expected.");
		}

	}
	
	/**
	 * Verify if the next token represents a boolean term.
	 * @return <code>true</code> if the next token represents a boolean term.
	 */
	private boolean isBooleanTerm() {
		return KeyWord.TRUE.hasSameToken( peekToken().getToken() ) ||
		KeyWord.FALSE.hasSameToken( peekToken().getToken() );
	}

	/**
	 * Check the syntaxe of an arithmetic expression.
	 */
	private void checkArithmeticExpression() {
		checkArithmeticTerm();

		if (isSignal(Signal.ADD_OP) || isSignal(Signal.MINUS_OP)){
			String symbol = peekToken().getToken();
			pushNewToken();
			checkArithmeticExpression();
			semanticAnalyser.verifyArithmeticTypeCompatibility();
			
			//Arithmetic code generation <AG3>
			String oper1 = codeGenerator.pop(CodeGenerator.Stack.PcO);
			String oper2 = codeGenerator.pop(CodeGenerator.Stack.PcO);
			String result = codeGenerator.makeTemp();
			codeGenerator.emit(result, symbol, oper2, oper1);
			codeGenerator.push(CodeGenerator.Stack.PcO, result);
		}
	}
	
	/**
	 * Check the syntaxe of an arithmetic term.
	 */
	private void checkArithmeticTerm() {
		checkArithmeticFactor();
		if (isSignal(Signal.TIMES_OP) || isSignal(Signal.DIVISION_OP)){
			String symbol = peekToken().getToken();
			pushNewToken();
			checkArithmeticTerm();
			semanticAnalyser.verifyArithmeticTypeCompatibility();
			
			//Arithmetic code generation <AG4>
			String oper1 = codeGenerator.pop(CodeGenerator.Stack.PcO);
			String oper2 = codeGenerator.pop(CodeGenerator.Stack.PcO);
			String result = codeGenerator.makeTemp();
			codeGenerator.emit(result, symbol, oper2, oper1);
			codeGenerator.push(CodeGenerator.Stack.PcO, result);
		}
	}
	
	/**
	 * Check the syntaxe of an arithmetic factor.
	 */
	private void checkArithmeticFactor() {
		if( isSignal(Signal.OPENING_PARENTHESES)){
			pushNewToken();
			checkArithmeticExpression();
			checkSignal(Signal.CLOSING_PARENTHESES);
			pushNewToken();
		}else if (isSignal(Signal.NUMBER)){
			asPushType(KeyWord.INT);
			
			//Arithmetic code generetion <AG6>
			codeGenerator.push(CodeGenerator.Stack.PcO, peekToken().getToken());
			
			pushNewToken();
			
			// Condi��o necess�ria para quando h� uma opera��o artim�tica sem operador
			if(isSignal(Signal.IDENTIFIER) || isSignal(Signal.NUMBER)){
				throw new SyntaxException("Arithmetic operator is missing.");
			}
			
		}else if (isSignal(Signal.IDENTIFIER)){
			semanticAnalyser.pushIdentifierType(SemanticTuple.Class.VARIABLE, buffer);
			
			//Arithmetic code generetion <AG5>
			codeGenerator.push(CodeGenerator.Stack.PcO, peekToken().getToken());

			
			pushNewToken();
			
			// Condi��o necess�ria para quando h� uma opera��o artim�tica sem operador
			if(isSignal(Signal.IDENTIFIER) || isSignal(Signal.NUMBER)){
				throw new SyntaxException("Arithmetic operator is missing.");
			}
		}else if (isSignal(Signal.MINUS_OP)) {
			pushNewToken();
			
			//Condi��o necess�ria para um n�mero negativo 
			 if (isSignal(Signal.NUMBER)){
					asPushType(KeyWord.INT);
			}else if(isSignal(Signal.IDENTIFIER)){
				semanticAnalyser.pushIdentifierType(SemanticTuple.Class.VARIABLE, buffer);
			}else{
				throw new SyntaxException("Unexpected token " + peekToken());
			}
			
			//Code Generation action to a relational expression
			String result = codeGenerator.makeTemp();
			codeGenerator.emit(result, "-U", peekToken().getToken());
			codeGenerator.push(CodeGenerator.Stack.PcO, result);
 
			pushNewToken();
		} else if (isSignal(Signal.STRING)){
			asPushType(KeyWord.STRING);
			
			//Arithmetic code generetion <AG6>
			codeGenerator.push(CodeGenerator.Stack.PcO, peekToken().getToken());
			
			pushNewToken();
			
		} else if (isSignal(Signal.CHAR)){
			asPushType(KeyWord.CHAR);
			
			//Arithmetic code generetion <AG6>
			codeGenerator.push(CodeGenerator.Stack.PcO, peekToken().getToken());
			
			pushNewToken();
		}else{
			throw new SyntaxException("Unexpected token " + peekToken());
		}
	}

	/**
	 * Check if the next construction in the source code is a logic term.
	 */
	private void checkTerm() {
		if( ! (KeyWord.TRUE.hasSameToken( peekToken().getToken() ) ||
				KeyWord.FALSE.hasSameToken( peekToken().getToken() ) ||
				peekToken().getCode().equals( Signal.IDENTIFIER ) ||
				peekToken().getCode().equals( Signal.STRING ) ||
				peekToken().getCode().equals( Signal.NUMBER ) ) ){
			throw new SyntaxException("Expecting logic term and was " + peekToken());
		}
	}

	/**
	 * Check if the next construction in the source code is a composite expression.
	 */
	private void checkCompositeExpression() {
		pushNewToken();
		checkTerm();
		if((KeyWord.TRUE.hasSameToken( peekToken().getToken() ) ||
				KeyWord.FALSE.hasSameToken( peekToken().getToken()) )){
			semanticAnalyser.push(KeyWord.BOOLEAN);
		}else if(peekToken().getCode().equals(Signal.IDENTIFIER)){
			semanticAnalyser.pushIdentifierType(SemanticTuple.Class.VARIABLE, buffer);

		}else if(peekToken().getCode().equals(Signal.STRING)){
			asPushType(KeyWord.STRING);
		}else if(peekToken().getCode().equals(Signal.NUMBER)){
			asPushType(KeyWord.INT);
		}
		
	}

	/**
	 * Check if the next construction in the source code is a logic operand.
	 */
	private boolean isOperand() {
		return peekToken().getCode().equals( Signal.EQUAL_OP ) ||
		peekToken().getCode().equals( Signal.GREATER_OR_EQUAL_THAN_OP ) ||
		peekToken().getCode().equals( Signal.GREATER_THAN_OP ) ||
		peekToken().getCode().equals( Signal.LESS_THAN_OP ) ||
		peekToken().getCode().equals( Signal.LESS_OR_EQUAL_THAN_OP ) ||
		peekToken().getCode().equals( Signal.AND_OP ) ||
		peekToken().getCode().equals( Signal.OR_OP ) ||
		peekToken().getCode().equals( Signal.NOT_EQUALS_OP );
	}


	/**
	 * Check if the next construction in the source code is a else command
	 */
	private void checkElseCommand() {
		System.out.println("else >>>>>>>>>>>>>>>>>>>>");
		if(isKeyWord(KeyWord.ELSE)){
			pushNewToken();
			checkSignal( Signal.OPENING_BRACE );
			pushNewToken();
			checkBody();
			checkSignal( Signal.CLOSING_BRACE );
		}
	}

	/**
	 * Check if the next construction in the source code is a while command.
	 */
	private void checkWhileCommand() {
		
		//code generation action <AG7>
		String label = codeGenerator.makeLabel();
		codeGenerator.insert(label, codeGenerator.getNextCommandLine());
		codeGenerator.push(CodeGenerator.Stack.PcL, label);
		
		//code generation action <AG1>
		codeGenerator.resetTemp();
		
		pushNewToken();
		checkSignal( Signal.OPENING_PARENTHESES );
		pushNewToken();
		
		checkRelationalExpression();
		
		//Generation Code Action <AG4>
		String labelTemp = codeGenerator.makeLabel();
		codeGenerator.push(CodeGenerator.Stack.PcL, labelTemp);
		codeGenerator.emit(labelTemp, "jif");
		
		checkSignal( Signal.CLOSING_PARENTHESES );
		pushNewToken();
		checkSignal( Signal.OPENING_BRACE );
		pushNewToken();
		checkBody();
		
		String labelFim = codeGenerator.pop(CodeGenerator.Stack.PcL);
		String labelInicio = codeGenerator.pop(CodeGenerator.Stack.PcL);
		codeGenerator.emit(labelInicio, "jmp");
		codeGenerator.insert(labelFim, codeGenerator.getNextCommandLine());
	}

	/**
	 * Check if the next construction in the source code is an attribution command.
	 */
	private void checkAtributionCommand() {
		checkSignal(Signal.ATRIBUTION_OPERANT);
		
		asPushAtributionType();
		
		pushNewToken();
		if (isSignal(Signal.MINUS_OP)) {
			pushNewToken();
			checkSignal(Signal.NUMBER);
			asPushType(KeyWord.INT);
			
			codeGenerator.push(CodeGenerator.Stack.PcO, "-" + peekToken().getToken());

			pushNewToken();
		}else if (isKeyWord(KeyWord.CALL)){
			pushNewToken();
			checkSignal( Signal.OPENING_PARENTHESES );
			pushNewToken();
			checkSignal(Signal.IDENTIFIER);
			
			semanticAnalyser.pushIdentifierType(SemanticTuple.Class.METHOD_NAME, buffer);

			codeGenerator.push(CodeGenerator.Stack.PcO, peekToken().getToken());
			
			pushNewToken();
			
			checkSignal( Signal.CLOSING_PARENTHESES );
			pushNewToken();
		}else if (isKeyWord(KeyWord.READ)){
			asPushType(KeyWord.VOID);
			
			pushNewToken();
			checkSignal( Signal.OPENING_PARENTHESES );
			pushNewToken();
			checkSignal( Signal.CLOSING_PARENTHESES );
			pushNewToken();
		}else if (isKeyWord(KeyWord.TRUE) || isKeyWord(KeyWord.FALSE)){
			asPushType(KeyWord.BOOLEAN);
			
			codeGenerator.push(CodeGenerator.Stack.PcO, peekToken().getToken());

			pushNewToken();
		}else if (isSignal(Signal.STRING) ){
			asPushType(KeyWord.STRING);
			
			codeGenerator.push(CodeGenerator.Stack.PcO, peekToken().getToken());

			pushNewToken();
		}else if (isSignal(Signal.CHAR) ){
			asPushType(KeyWord.CHAR);
			codeGenerator.push(CodeGenerator.Stack.PcO, peekToken().getToken());
			pushNewToken();
		}else{
			checkExpression();
			if(isSignal(Signal.OPENING_PARENTHESES)){
				pushNewToken();
				checkSignal( Signal.CLOSING_PARENTHESES );
				pushNewToken();
			}
		}
		checkSignal(Signal.END_OF_COMMAND);
		semanticAnalyser.verifyAtributionCompatibility();
	}



	/**
	 * Verify the next token syntaxe.
	 */
	private void checkEvaluables() {
		pushNewToken();
		if ( isKeyWord( KeyWord.READ ) ){
			checkReadFunction();
		}else if (isSignal(Signal.MINUS_OP)){
			pushNewToken();
			checkSignal(Signal.NUMBER);
			pushNewToken();
			checkSignal(Signal.END_OF_COMMAND);
		}else if (isSignal(Signal.IDENTIFIER) || isSignal(Signal.NUMBER)){
			checkExpression();
			if (isSignal(Signal.END_OF_COMMAND)){
				return;
			}else if (isSignal(Signal.OPENING_PARENTHESES)){
				pushNewToken();
				checkSignal(Signal.CLOSING_PARENTHESES);
				pushNewToken();
				checkSignal(Signal.END_OF_COMMAND);
				return;
			}
		}else if (isSignal(Signal.STRING) || KeyWord.TRUE.hasSameToken( peekToken().getToken() ) ||	
				KeyWord.FALSE.hasSameToken( peekToken().getToken() )){
		}else{
			throw new SyntaxException("Evaluable expected and was " + peekToken());
		}
	}

	/**
	 * Check if the next construction in the source code is the read function.
	 * @return true if the next token is the read function, otherwise false.
	 */
	private void checkReadFunction() {
		asPushType(KeyWord.VOID);
		pushNewToken();
		checkSignal( Signal.OPENING_PARENTHESES );
		pushNewToken();
		checkSignal( Signal.CLOSING_PARENTHESES );
		pushNewToken();
		checkSignal( Signal.END_OF_COMMAND );
	}

	/**
	 * It pushes the word on the top of the stack.
	 * @param word The word to be pushed.
	 */
	private void asPushType(KeyWord word) {
		semanticAnalyser.push(word);		
	}
}